//
//  RxSwiftSubjectsViewController.swift
//  DemoProject
//
//  Created by Hao on 2018/8/4.
//  Copyright © 2018年 hao. All rights reserved.
//

import UIKit
import RxSwift
import RxCocoa

/// Subjects有四种:  PublishSubject、BehaviorSubject、ReplaySubject、Variables(BehaviorRelay)
/// 他们都是 Observable，他们的订阅者都能收到他们发出的新的 Event。
/// 直到 Subject 发出 .complete 或者 .error 的 Event 后，该 Subject 便终结了，同时它也就不会再发出 .next 事件。
/// 对于那些在 Subject 终结后再订阅他的订阅者，也能收到 subject 发出的一条 .complete 或 .error 的 event，告诉这个新的订阅者它已经终结了。
/// 最大的区别只是在于：当一个新的订阅者刚订阅它的时候，能不能收到 Subject 以前发出过的旧 Event，如果能的话又能收到多少个。
class RxSwiftSubjectsViewController: BaseViewController {

    /// PublishSubject 是最普通的 Subject，它不需要初始值就能创建。
    /// PublishSubject 的订阅者从他们开始订阅的时间点起，可以收到订阅后 Subject 发出的新 Event，而不会收到他们在订阅前已发出的 Event
    let publishSubject = PublishSubject<String>()
    
    /// BehaviorSubject 需要通过一个默认初始值来创建。
    /// 当第一个订阅者来订阅它的时候，这个订阅者会立即收到 BehaviorSubjects 上一个发出的 event(即携带BehaviorSubject初始化时的值)。之后就跟正常的情况一样，它也会接收到 BehaviorSubject 之后发出的新的 event。
    let behaviorSubject = BehaviorSubject<String>.init(value: "BehaviorSubject init Value")
    
    /// ReplaySubject 在创建时候需要设置一个 bufferSize，表示它对于它发送过的 event 的缓存个数
    /// bufferSize: 缓存的事件个数，如果 ReplaySubject 发送了 3 个.next事件，就会将后发送的2个事件缓存，如果有subscriber 订阅了这个 ReplaySubject，那么这个 subscriber(必须在.next事件之后订阅才会收到缓存的事件，之前的订阅者只会收到最新的事件) 就会立即收到前面缓存的两个 .next 的 event
    /// 如果一个 subscriber 订阅已经结束的 ReplaySubject，除了会收到缓存的 .next 的 event 外，还会收到那个终结的 .error 或者 .complete 的 event。
    let replaySubject = ReplaySubject<String>.create(bufferSize: 2)
    
    /// This concept will be deprecated from RxSwift but offical migration path hasn’t been decided yet. (即将被废弃，但官方还未确定，建议使用 Varible 的地方都改为 BehaviorRelay 作为替代)
    /// Variable 其实就是对 BehaviorSubject 的封装，所以它也必须要通过一个默认的初始值进行创建。
    /// Variable 具有 BehaviorSubject 的功能，能够向它的订阅者发出上一个 event 以及之后新创建的 event。
    /// 不同的是，Variable 还把会把当前发出的值保存为自己的状态。同时它会在销毁时自动发送 .complete 的 event，不需要也不能手动给 Variables 发送 completed 或者 error 事件来结束它。
    /// 简单地说就是 Variable 有一个 value 属性，我们改变这个 value 属性的值就相当于调用一般 Subjects 的 onNext() 方法，而这个最新的 onNext() 的值就被保存在 value 属性里了，直到我们再次修改它。
//    let variable = Variable<String>.init("Variable init value")
    /// Variable的替代， value 属性变为只读，获取最新的值， 通过 accept() 方法设置值, 可直接调用订阅 subscribe()
//    let behaviorRelay = BehaviorRelay<String>(value: "BehaviorRelay init value")
    
    let disposeBag = DisposeBag()
    
    override func viewDidLoad() {
        super.viewDidLoad()
//        testPublishSubject()
//        testBehaviorSubject()
//        testReplaySubject()
//        testVariable()
        testBehaviorRelay()
    }

    override func viewDidDisappear(_ animated: Bool) {
        super.viewDidDisappear(animated)
//        _ = DisposeBag()
    }
    
}

// MARK: PublishSubject
extension RxSwiftSubjectsViewController {
    
    /**
     运行结果:
         第1次订阅：publishSubject_222
         第1次订阅：publishSubject_333
         第2次订阅：publishSubject_333
         第1次订阅订阅完成：onCompleted
         第2次订阅订阅完成：onCompleted
         第3次订阅订阅完成：onCompleted
     */
    fileprivate func testPublishSubject() {
        // 由于没有任何订阅者，这条信息并不会打印
        publishSubject.onNext("publishSubject_111")
        
        // 第一次订阅
        publishSubject.subscribe(onNext: { (string) in
            print(info: "第1次订阅：\(string)")
        }, onError: { (error) in
            
        }, onCompleted: {
            print(info: "第1次订阅订阅完成：onCompleted")
        }).disposed(by: disposeBag)
        
        // 再次发送消息，因为已经有订阅者所以会输出
        publishSubject.onNext("publishSubject_222")
        
        // 第二次订阅 publishSubject
        publishSubject.subscribe(onNext: { (string) in
            print(info: "第2次订阅：\(string)")
        }, onError: { (error) in
            
        }, onCompleted: {
            print(info: "第2次订阅订阅完成：onCompleted")
        }).disposed(by: disposeBag)
        
        // 第三次发出消息
        publishSubject.onNext("publishSubject_333")
        
        // 结束publishSubject
        publishSubject.onCompleted()
        
        // publishSubject完成后再发出.next事件
        publishSubject.onNext("publishSubject_444")
        
        publishSubject.subscribe(onNext: { (string) in
            print(info: "第3次订阅：\(string)")
        }, onError: { (error) in
            
        }, onCompleted: {
            print(info: "第3次订阅订阅完成：onCompleted")
        }).disposed(by: disposeBag)
    }
    
}

// MARK: BehaviorSubject
extension RxSwiftSubjectsViewController {
    
    /**
     运行结果:
         第1次订阅：next(BehaviorSubject init Value)
         第1次订阅：next(BehaviorSubject_222)
         第1次订阅：error(Error Domain=local BehaviorSubject error Code=0 "(null)")
         第2次订阅：error(Error Domain=local BehaviorSubject error Code=0 "(null)")
         第3次订阅：error(Error Domain=local BehaviorSubject error Code=0 "(null)")
     */
    fileprivate func testBehaviorSubject() {
        // 第一次订阅
        behaviorSubject.subscribe { (event) in
            print(info: "第1次订阅：\(event)")
        }.disposed(by: disposeBag)
        
        print(info: "----------------")
        
        // 发送next事件
        behaviorSubject.onNext("BehaviorSubject_222")
        
        print(info: "----------------")
        
        // 发送错误事件(表示已经结束，后面再次发送next就只会收到error)
        behaviorSubject.onError(NSError(domain: "local BehaviorSubject error", code: 0, userInfo: nil))
        
        // 第二次订阅
        behaviorSubject.subscribe { (event) in
            print(info: "第2次订阅：\(event)")
        }.disposed(by: disposeBag)
        
        // 再次发送next事件
        behaviorSubject.onNext("BehaviorSubject_333")
        // 第三次订阅
        behaviorSubject.subscribe { (event) in
            print(info: "第3次订阅：\(event)")
        }.disposed(by: disposeBag)
    }
    
}

// MARK: ReplaySubject
extension RxSwiftSubjectsViewController {
    
    /**
     运行结果:
         第1次订阅：next(ReplaySubject_222)
         第1次订阅：next(ReplaySubject_333)
         ----------------
         第1次订阅：next(ReplaySubject_444)
         第2次订阅：next(ReplaySubject_333)
         第2次订阅：next(ReplaySubject_444)
         ----------------
         第1次订阅：completed
         第2次订阅：completed
         第3次订阅：next(ReplaySubject_333)
         第3次订阅：next(ReplaySubject_444)
         第3次订阅：completed
         第4次订阅：next(ReplaySubject_333)
         第4次订阅：next(ReplaySubject_444)
         第4次订阅：completed
     */
    fileprivate func testReplaySubject() {
        // 连续发送三个next事件
        replaySubject.onNext("ReplaySubject_111")
        replaySubject.onNext("ReplaySubject_222")
        replaySubject.onNext("ReplaySubject_333")
        
        replaySubject.subscribe { (event) in
            print(info: "第1次订阅：\(event)")
        }.disposed(by: disposeBag)
        
        print(info: "----------------")
        
        // 这个事件发送之前的订阅者只会收到这个最新发出的事件，并不会收到缓存的事件
        replaySubject.onNext("ReplaySubject_444")
        replaySubject.subscribe { (event) in
            print(info: "第2次订阅：\(event)")
        }.disposed(by: disposeBag)
        
        print(info: "----------------")
        
//        replaySubject.onNext("ReplaySubject_555")
        
        // 结束replaySubject
        replaySubject.onCompleted()
        
        replaySubject.subscribe { (event) in
            print(info: "第3次订阅：\(event)")
        }.disposed(by: disposeBag)

        replaySubject.subscribe { (event) in
            print(info: "第4次订阅：\(event)")
        }.disposed(by: disposeBag)
    }
    
}

// MARK: Variable
extension RxSwiftSubjectsViewController {
    
    /**
     运行结果:
         "第1次订阅：next(variable_222)"
         "第1次订阅：next(variable_333)"
         "第2次订阅：next(variable_333)"
         "第1次订阅：next(variable_444)"
         "第2次订阅：next(variable_444)"
         "第1次订阅：completed"
         "第2次订阅：completed"
     */
    fileprivate func testVariable() {
        // variable 是对 BehaviorSubject 的封装，改变 value 的值相当于发送.next事件, 同时它会在销毁时自动发送 .complete 的 event，不需要也不能手动给 Variables 发送 completed 或者 error 事件来结束它
        let variable = Variable<String>.init("Variable init value")
        variable.value = "variable_222"
        // 第1次订阅
        variable.asObservable().subscribe {
            print(info: "第1次订阅：\($0)")
        }.disposed(by: disposeBag)
        
        variable.value = "variable_333"
        variable.asObservable().subscribe {
            print(info: "第2次订阅：\($0)")
        }.disposed(by: disposeBag)
        
        variable.value = "variable_444"
    }
    
}

// MARK: BehaviorRelay (Variable的替代)
extension RxSwiftSubjectsViewController {
    
    /**
     运行结果:
         "第1次订阅：next([\"1\"])"
         "第1次订阅：next([\"1\", \"2\", \"3\"])"
         "第2次订阅：next([\"1\", \"2\", \"3\"])"
         "behaviorRelay 最新的值: ", "[\"1\", \"2\", \"3\"]"
         "第1次订阅：next([\"1\", \"2\", \"3\", \"4\", \"5\"])"
         "第2次订阅：next([\"1\", \"2\", \"3\", \"4\", \"5\"])"
         "第3次订阅：next([\"1\", \"2\", \"3\", \"4\", \"5\"])"
         "第1次订阅：next([\"1\", \"2\", \"3\", \"4\", \"5\", \"6\", \"7\"])"
         "第2次订阅：next([\"1\", \"2\", \"3\", \"4\", \"5\", \"6\", \"7\"])"
         "第3次订阅：next([\"1\", \"2\", \"3\", \"4\", \"5\", \"6\", \"7\"])"
     */
    fileprivate func testBehaviorRelay() {
        let behaviorRelay = BehaviorRelay<[String]>(value: ["1"])
        behaviorRelay.subscribe {
            print(info: "第1次订阅：\($0)")
        }.disposed(by: disposeBag)
        
        behaviorRelay.accept(behaviorRelay.value + ["2", "3"])
        behaviorRelay.asObservable().subscribe {
            print(info: "第2次订阅：\($0)")
        }.disposed(by: disposeBag)
        
        print(info: "behaviorRelay 最新的值: \(behaviorRelay.value.description)")
        
        behaviorRelay.accept(behaviorRelay.value + ["4", "5"])
        behaviorRelay.subscribe {
            print(info: "第3次订阅：\($0)")
        }.disposed(by: disposeBag)
        
        behaviorRelay.accept(behaviorRelay.value + ["6", "7"])
    }
    
}






